#include <stdio.h>
#include <assert.h>

#include <CompileVisitor.h>

#include "AstNodeBooleanOperator.h"
#include "AstNodeCompareExpression.h"

AstNodeBooleanOperator::AstNodeBooleanOperator(
    AstNodeBooleanOperator * left, AstNodeBooleanOperator  * rite, char oper)
{
  assert(oper!=_not || rite==0);
  this->left=left;
  this->rite=rite;
  this->oper=oper;
  this->cmp=0;
}

void AstNodeBooleanOperator::compile(CompileVisitor * visitor)
{
  visitor->compile(this);
}

AstNodeBooleanOperator::AstNodeBooleanOperator(
    AstNodeCompareExpression * cmp)
{
  this->left=0;
  this->rite=0;
  this->oper=0;
  this->cmp=cmp;
}

void AstNodeBooleanOperator::dump(int level)
{
  if(cmp) {
    cmp->dump(level+1);
  } else {
    printf("<<");
    left->dump(level+1);
    switch(oper) {
      case _and:
        printf(" .and. ");
        break;
      case _or:
        printf(" .or. ");
        break;
      case _not:
        printf(" .not. ");
        break;
      case _nop:
        printf(" .nop. ");
        break;
      default:
        assert(0);
    }
    if(rite)
      rite->dump(level+1);
    printf(">>");
  }
}

#if 0
int AstNodeBooleanOperator::compile(
    ClassFile * klass, MethodInfo * method)
{
  assert(0); // TODO: throw: cannot compile this, use compileWithReloc
}

int AstNodeBooleanOperator::compileWithReloc(
    ClassFile * klass, MethodInfo * method,
    RelocTable & relocOnTrue,
    RelocTable & relocOnFalse)
{
  if(cmp) {
    u1 opcode=cmp->getOpcodeForFalse();
    cmp->compile(klass,method);
    relocOnFalse.push_back(method->getAP());
    method->assemble(opcode,0);
  } else {
    RelocTable local_relocOnTrue;
    RelocTable local_relocOnFalse;
    u4 targetTrue;
    u4 targetFalse;
    switch(oper) {
      case _and:
        left->compileWithReloc(klass,method,
            local_relocOnTrue,
            relocOnFalse);
        targetTrue=method->getAP();

        local_relocOnTrue.reloc(method,targetTrue);
        local_relocOnTrue.clear();

        rite->compileWithReloc(klass,method,
            relocOnTrue,
            relocOnFalse);
        break;
      case _or:
        left->compileWithReloc(klass,method,
            relocOnTrue,
            local_relocOnFalse);

        relocOnTrue.push_back(method->getAP());
        method->assemble(OPC_goto,0);

        targetFalse=method->getAP();
        local_relocOnFalse.reloc(method,targetFalse);

        rite->compileWithReloc(klass,method,
            relocOnTrue,
            relocOnFalse);
        break;


      case _not:
        left->compileWithReloc(klass,method,
            relocOnFalse,relocOnTrue);
        relocOnFalse.push_back(method->getAP());
        method->assemble(OPC_goto,0);

        break;

      default:
        assert(0);
    }
  }
  return 0;
}
#endif
